package application

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"gitee.com/baal1990/gitee.com/baal1990/cmd/server_attence/app/business/overtime"
	"gitee.com/baal1990/gitee.com/baal1990/cmd/server_attence/app/business/vacation"
	"gitee.com/baal1990/gitee.com/baal1990/cmd/server_attence/app/dao"
	"gitee.com/baal1990/gitee.com/baal1990/cmd/server_attence/app/entity"
	"gitee.com/baal1990/gitee.com/baal1990/cmd/server_attence/app/global"
	"gitee.com/baal1990/gitee.com/baal1990/pkg/db"
	"gitee.com/baal1990/gitee.com/baal1990/pkg/model"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// ********************************************
// Func  ：查询所有申请，列表返回
// Method：GET
// Usage ：
// ********************************************
func QueryApplicationList(c *gin.Context) {
	requester := c.MustGet("USER").(*entity.Employee) //请求人

	pageSize, err1 := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
	if err1 != nil {
		global.Log.Error("QueryApplicationList input param pagesize error:", zap.Any("error", err1))
		c.JSON(http.StatusOK, model.Fail("请求参数错误"))
		return
	}

	page, err2 := strconv.Atoi(c.DefaultQuery("page", "1"))
	if err2 != nil {
		global.Log.Error("QueryApplicationList input param page error:", zap.Any("error", err2))
		c.JSON(http.StatusOK, model.Fail("请求参数错误"))
		return
	}

	applicationType, err2 := strconv.Atoi(c.DefaultQuery("applicationType", "0"))
	if err2 != nil {
		global.Log.Error("QueryApplicationList input param applicationType error:", zap.Any("error", err2))
		c.JSON(http.StatusOK, model.Fail("请求参数错误"))
		return
	}

	//指定部门，单选，若有部门只能支持1个
	var deptIdList []int64
	deptIdsStr := c.DefaultQuery("deptId", "") //部门列表
	if deptIdsStr != "" {
		idList := strings.Split(deptIdsStr, ",")
		for _, idstr := range idList {
			id, err := strconv.ParseInt(idstr, 10, 64)
			if err == nil {
				deptIdList = append(deptIdList, id)
			}
		}
	}

	//指定申请者
	var applicantIdList []int64
	applicantIdsStr := c.DefaultQuery("applicantId", "") //人员列表
	if applicantIdsStr != "" {
		idList := strings.Split(applicantIdsStr, ",")
		for _, idstr := range idList {
			id, err := strconv.ParseInt(idstr, 10, 64)
			if err == nil {
				applicantIdList = append(applicantIdList, id)
			}
		}
	}

	detailType, err := strconv.Atoi(c.DefaultQuery("detailType", ""))
	if err != nil {
		detailType = 0
		global.Log.Info("QueryApplicationList detailType is missing.")
	}

	status, err := strconv.Atoi(c.DefaultQuery("status", "0"))
	if err != nil {
		global.Log.Info("QueryApplicationList input param status missing:", zap.Any("error", err))
	}

	startDate := c.DefaultQuery("startDate", "")
	endDate := c.DefaultQuery("endDate", "")

	//下面校验各个角色的适用权限范围
	if requester.Role == entity.EEmployeeRole_Outsourcing { //如果是员工，只能看自己了
		if len(applicantIdList) > 1 {
			global.Log.Error("QueryApplicationList employee requester has no auth:",
				zap.Any("applicantIds", applicantIdList), zap.Any("requester", requester.Id))
			c.JSON(http.StatusOK, model.Fail("只能查询自己的信息"))
			return
		}
		if len(applicantIdList) == 1 {
			applicantId := applicantIdList[0]
			if (applicantId != requester.Id) && applicantId > 0 {
				//请求数据与请求者身份不匹配
				global.Log.Error("QueryApplicationList employee requester has no auth:",
					zap.Any("applicantId", applicantId), zap.Any("requester", requester.Id))
				c.JSON(http.StatusOK, model.Fail("查询目标与请求者身份不一致"))
				return
			}
		}
	} else if requester.Role == entity.EEmployeeRole_DeptLeader {
		if len(deptIdList) > 1 {
			global.Log.Error("QueryApplicationList leader requester has no auth for other dept:",
				zap.Any("Req deptId", deptIdList), zap.Any("requester", requester.Id))
			c.JSON(http.StatusOK, model.Fail("查询请求者不能查询其它部门的数据"))
			return
		}
		if len(deptIdList) == 1 {
			deptId := deptIdList[0]
			if deptId != requester.DeptId && deptId > 0 {
				global.Log.Error("QueryApplicationList leader requester has no auth for other dept:",
					zap.Any("Req deptId", deptId), zap.Any("requester deptId", requester.DeptId))
				c.JSON(http.StatusOK, model.Fail("查询请求者不能查询其它部门的数据"))
				return
			}
		}

	} else if requester.Role == entity.EEmployeeRole_Hr {
		//查看所有外包员工.

	}

	total, list, err := dao.QueryApplicationList(page, pageSize, detailType,
		status, applicationType, startDate, endDate, applicantIdList, deptIdList)
	if err != nil {
		global.Log.Error("QueryApplicationList failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("查询失败"))
	} else {

		type OutputList struct { //列表查询输出
			Total int64
			List  []*entity.OutputApplicationInfo
		}

		employeeMap := dao.GetAllEmployeeMap()
		if employeeMap != nil {
			for _, appinfo := range list {
				if appinfo == nil {
					continue
				}
				if appinfo.ApproverId > 0 {
					employee, has := employeeMap[appinfo.ApproverId]
					if has {
						appinfo.ApproverName = employee.Name //审批人
					}
				}

				if appinfo.ApplicantId > 0 {
					employee, has := employeeMap[appinfo.ApplicantId]
					if has {
						appinfo.ApplicantName = employee.Name //申请人
					}
				}
			}
		}

		output := &OutputList{
			Total: total,
		}

		for _, appinfo := range list {
			if appinfo == nil {
				continue
			}
			info := &entity.OutputApplicationInfo{
				Id:              strconv.FormatInt(appinfo.Id, 10),
				ApplicantId:     strconv.FormatInt(appinfo.ApplicantId, 10),
				ApproverId:      strconv.FormatInt(appinfo.ApproverId, 10), //审批人ID
				DeptId:          strconv.FormatInt(appinfo.DeptId, 10),     //部门ID
				Reason:          appinfo.Reason,
				StartDate:       appinfo.StartDate,
				EndDate:         appinfo.EndDate,
				Duration:        appinfo.Duration,
				CreateAt:        appinfo.CreateAt,
				ApproveAt:       appinfo.ApproveAt,
				Type:            appinfo.Type,          //类型 0、不限、1工作日、2周末、3法定假日、4其它
				Status:          appinfo.Status,        //0:draft，1：send；2：delete；3:recall，4:refuse
				Note:            appinfo.Note,          //备注
				ApplicantName:   appinfo.ApplicantName, //申请人姓名
				ApproverName:    appinfo.ApproverName,  //审批人姓名
				DeptName:        appinfo.DeptName,      //部门名称	employee.id
				DurationDay:     appinfo.DurationDay,   // 时长（天，0.5起跳）
				ApplyType:       appinfo.ApplyType,     //类型 0、不限、1工作日、2周末、3法定假日、4其它
				ApplyStatus:     appinfo.ApplyStatus,   //0:draft，1：send；2：delete；3:recall，4:refuse
				ApplicationType: appinfo.ApplicationType,
			}
			output.List = append(output.List, info)
		}
		c.JSON(http.StatusOK, model.SuccessObject("操作成功", output))
		global.Log.Info("QueryApplicationList success.", zap.Any("application list", output))
	}
}

// ********************************************
// Func  ：查询指定申请详情
// Method：GET
// Usage ：
// ********************************************
func QueryApplicationDetail(c *gin.Context) {
	requester := c.MustGet("USER").(*entity.Employee) //请求人
	applicationId, err := strconv.ParseInt(c.DefaultQuery("overtimeId", ""), 10, 64)
	if err != nil {
		global.Log.Error("QueryApplicationDetail overtimeId is lost.")
		c.JSON(http.StatusOK, model.Fail("未指明申请ID"))
		return
	}
	if applicationId <= 0 {
		global.Log.Error("QueryApplicationDetail applicationId is lost.")
		c.JSON(http.StatusOK, model.Fail("未指明申请ID"))
		return
	}

	applicationInfo, err := dao.QueryApplicationInfo(applicationId)
	if err != nil {
		global.Log.Error("QueryApplicationDetail failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("查询申请详情失败"))
		return
	}
	if applicationInfo == nil {
		c.JSON(http.StatusOK, model.Fail("未找到指定申请"))
		global.Log.Info("QueryApplicationDetail application detail info is nil.")
		return
	}

	if requester.Role == entity.EEmployeeRole_Outsourcing { //如果是员工，只能看自己了
		if requester.Id != applicationInfo.ApplicantId {
			//请求数据与请求者身份不匹配
			global.Log.Error("QueryApplicationDetail employee requester has no auth:",
				zap.Any("applicantId", applicationInfo.ApplicantId), zap.Any("requester", requester.Id))
			c.JSON(http.StatusOK, model.Fail("查询目标与请求者身份不匹配"))
			return
		}
	}

	var output entity.OutputApplicationInfo
	output.Id = strconv.FormatInt(applicationInfo.Id, 10)
	output.ApplicantId = strconv.FormatInt(applicationInfo.ApplicantId, 10)
	output.ApproverId = strconv.FormatInt(applicationInfo.ApproverId, 10) //审批人ID
	output.DeptId = strconv.FormatInt(applicationInfo.DeptId, 10)         //部门ID
	output.Reason = applicationInfo.Reason
	output.StartDate = applicationInfo.StartDate
	output.EndDate = applicationInfo.EndDate
	output.Duration = applicationInfo.Duration
	output.CreateAt = applicationInfo.CreateAt
	output.ApproveAt = applicationInfo.ApproveAt
	output.Type = applicationInfo.Type                       //类型 0、不限、1工作日、2周末、3法定假日、4其它
	output.Status = applicationInfo.Status                   //0:draft，1：send；2：delete；3:recall，4:refuse
	output.Note = applicationInfo.Note                       //备注
	output.ApplicationType = applicationInfo.ApplicationType //
	output.ApplicantName = applicationInfo.ApplicantName     //申请人姓名
	output.ApproverName = applicationInfo.ApproverName       //审批人姓名
	output.DeptName = applicationInfo.DeptName               //部门名称	employee.id
	output.DurationDay = applicationInfo.DurationDay         // 时长（天，0.5起跳）
	output.ApplyType = applicationInfo.ApplyType             //类型 0、不限、1工作日、2周末、3法定假日、4其它
	output.ApplyStatus = applicationInfo.ApplyStatus         //0:draft，1：send；2：delete；3:recall，4:refuse
	output.ApplicationType = applicationInfo.ApplicationType //

	c.JSON(http.StatusOK, model.SuccessObject("操作成功", output))
	global.Log.Info("QueryApplicationDetail success.", zap.Any("applicationInfo", applicationInfo))
}

// ********************************************
// Func  ：添加新申请
// Method：POST
// Usage ：
// ********************************************
func AddNewApplication(c *gin.Context) {

	//todo. 此处需要判别当前请求发起者身份，仅外包员工才能操作权限
	requester := c.MustGet("USER").(*entity.Employee) //请求人
	if requester.Role != entity.EEmployeeRole_Outsourcing {
		global.Log.Error("AddNewApplication role error.", zap.Any("requester", requester))
		c.JSON(http.StatusOK, model.Fail("暂不支持非外包员工申请操作"))
		return
	}

	var application entity.Application
	var err error

	application.ApplicationType, err = strconv.Atoi(c.DefaultPostForm("applicationType", "0"))
	if err != nil {
		global.Log.Error("AddNewApplication applicationType error:", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("请求参数错误"))
		return
	}
	if application.ApplicationType != entity.EApplicationType_Overtime &&
		application.ApplicationType != entity.EApplicationType_Vacation {
		global.Log.Error("AddNewApplication input param applicationType error:",
			zap.Any("ApplicationType", application.ApplicationType))
		c.JSON(http.StatusOK, model.Fail("未支持的请求类型"))
		return
	}

	application.ApplicantId, err = strconv.ParseInt(c.DefaultPostForm("applicantId", ""), 10, 64)
	if err != nil {
		global.Log.Error("AddNewApplication applicant id is missing.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("未指明申请人"))
		return
	}
	application.DeptId, err = strconv.ParseInt(c.DefaultPostForm("deptId", ""), 10, 64)
	application.Reason = c.DefaultPostForm("reason", "")

	startDateStr := c.DefaultPostForm("startDate", "")
	endDateStr := c.DefaultPostForm("endDate", "")
	if startDateStr == "" || endDateStr == "" {
		global.Log.Error("AddNewOvertime startDate and endDate cannot be none.")
		c.JSON(http.StatusOK, model.Fail("开始和结束时间必须明确"))
		return
	}

	dtLayout := "2006-01-02 15:04:05"
	loc := db.TZLocation()
	application.StartDate, err = time.ParseInLocation(dtLayout, startDateStr, loc)
	if err != nil {
		global.Log.Error("AddNewOvertime startDate convert failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("开始时间解析不正确"))
		return
	}
	application.EndDate, err = time.ParseInLocation(dtLayout, endDateStr, loc)
	if err != nil {
		global.Log.Error("AddNewOvertime endDate convert failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("结束时间解析不正确"))
		return
	}

	duration, err := strconv.ParseFloat(c.DefaultPostForm("duration", ""), 32)
	if err == nil {
		application.Duration = float32(duration)
	} else {
		if application.ApplicationType == entity.EApplicationType_Overtime {
			application.Duration = overtime.DurationCalc(application.StartDate, application.EndDate)
		} else if application.ApplicationType == entity.EApplicationType_Vacation {
			application.Duration = vacation.DurationDayCalc(application.StartDate, application.EndDate)
		}

		if application.Duration <= 0 {
			global.Log.Error("AddNewOvertime duration must >0.", zap.Any("error", err))
			c.JSON(http.StatusOK, model.Fail("结束时间须晚于开始时间"))
			return
		}
	}

	newer, err := dao.InsertApplication(application)
	if err != nil {
		global.Log.Error("AddNewOvertime failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("添加部门失败"))
	} else {
		if nil == newer {
			global.Log.Error("AddNewOvertime failed.", zap.Any("error", err))
			c.JSON(http.StatusOK, model.Fail("添加部门失败"))
			return
		}
		var output entity.OutputOvertimeInfo
		output.Id = strconv.FormatInt(newer.Id, 10)
		output.ApplicantId = strconv.FormatInt(newer.ApplicantId, 10)
		output.ApproverId = strconv.FormatInt(newer.ApproverId, 10) //审批人ID
		output.DeptId = strconv.FormatInt(newer.DeptId, 10)         //部门ID
		output.Reason = newer.Reason
		output.StartDate = newer.StartDate
		output.EndDate = newer.EndDate
		output.Duration = newer.Duration
		output.CreateAt = newer.CreateAt
		output.ApproveAt = newer.ApproveAt
		output.Type = newer.Type     //类型 0、不限、1工作日、2周末、3法定假日、4其它
		output.Status = newer.Status //0:draft，1：send；2：delete；3:recall，4:refuse
		output.Note = newer.Note     //备注
		//output.ApplicantName = newer.ApplicantName                  //申请人姓名
		//output.ApproverName = overtimeInfo.ApproverName             //审批人姓名
		//output.DeptName = overtimeInfo.DeptName                     //部门名称	employee.id
		output.DurationDay = application.Duration                      // 时长（天，0.5起跳）
		output.ApplyType = dao.ApplicationDetailTypeString(newer.Type) //0不限、1病假、2事假、3年假、4婚假、5丧假、6工作日班班、7周末班、8法定假日
		output.ApplyStatus = dao.ApplicationStatusString(newer.Status) //0:draft，1：send；2：delete；3:recall，4:refuse
		output.ApplicationType = newer.ApplicationType
		c.JSON(http.StatusOK, model.SuccessObject("操作成功", output))
		global.Log.Info("AddNewOvertime success.", zap.Any("new", newer))

		var op entity.OperatingRecord
		op.EmployeeId = application.ApplicantId
		op.Event = "新增申请 [status:" + strconv.Itoa(application.Status) + "] 部门:" + fmt.Sprint(application.DeptId)
		dao.InsertOpRecord(op)
	}
}

// ********************************************
// Func  ：审批申请（通过或拒绝）
// Method：POST
// Usage ：
// Param: overtimeId、approverId、status
// ********************************************
func ApplicationApprove(c *gin.Context) {

	//todo .此处需要判别当前请求发起者身份，如果非主管和Hr，则驳回，无此操作权限
	requester := c.MustGet("USER").(*entity.Employee) //请求人
	if requester.Role != entity.EEmployeeRole_DeptLeader && requester.Role != entity.EEmployeeRole_Hr {
		global.Log.Error("ApplicationApprove role error.")
		c.JSON(http.StatusOK, model.Fail("HR或部门主管审批加班"))
		return
	}

	var application entity.Application
	var err error
	application.Id, err = strconv.ParseInt(c.DefaultPostForm("applicationId", ""), 10, 64)
	if err != nil {
		global.Log.Error("ApplicationApprove overtime is lost.")
		c.JSON(http.StatusOK, model.Fail("未指明加班申请ID"))
		return
	}

	p, err := dao.QueryApplicationDetail(application.Id)
	if err != nil {
		global.Log.Error("ApplicationApprove application is lost.", zap.Any("application", application.Id))
		c.JSON(http.StatusOK, model.Fail("未找到申请信息"))
		return
	}
	if nil == p {
		global.Log.Error("ApplicationApprove application is lost.", zap.Any("application", application.Id))
		c.JSON(http.StatusOK, model.Fail("未找到申请信息"))
		return
	}
	application = *p

	application.ApproverId, err = strconv.ParseInt(c.DefaultPostForm("approverId", ""), 10, 64)
	if err != nil { //审批人为空
		if application.DeptId > 0 || application.ApproverId <= 0 {
			//有部门了
			deptDetail, err := dao.QueryDeptartmentDetail(application.DeptId)
			if err != nil {
				global.Log.Error("ApplicationApprove QueryDeptartmentDetail failed.DeptId:",
					zap.Any("DeptId", application.DeptId))
			} else {
				if deptDetail.DeptHeadId > 0 {
					if deptDetail.DeptHeadId != requester.Id {
						global.Log.Error("requester is not the leader of dept",
							zap.Any("DeptId", deptDetail.DeptHeadId), zap.Any("requester.Id", requester.Id))
					}
					application.ApproverId = deptDetail.DeptHeadId
				} else {
					global.Log.Error("there no leader in the department", zap.Any("DeptId", application.DeptId))
				}
			}
		}
	}

	application.ApproveAt = time.Now()
	application.Status, err = strconv.Atoi(c.DefaultPostForm("status", ""))
	if err != nil {
		global.Log.Error("ApplicationApprove status is error.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("未指明加班审批状态"))
		return
	}
	application.Note = c.DefaultPostForm("note", "")
	err = dao.UpdateApplication(application, "status,approve_at,note,approver_id")
	if err != nil {
		global.Log.Error("ApplicationApprove failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("更新部门失败"))
	} else {
		type Result struct {
			ApplicationId   string
			ApplicantId     string //申请人
			ApproverId      string //审批人
			DeptId          string //部门名称	employee.id
			Type            int
			Status          int
			DurationDay     float32 // 时长（天，0.5起跳）
			ApplyType       string  //类型 0、不限、1病假、2事假、3年假、4婚假、5丧家、6其它
			ApplyStatus     string  //0:draft，1：send；2：delete；3:recall，4:refuse
			Note            string
			ApplicationType int
		}
		result := &Result{
			ApplicationId:   strconv.FormatInt(application.Id, 10),
			ApplicantId:     strconv.FormatInt(application.ApplicantId, 10),
			ApproverId:      strconv.FormatInt(application.ApproverId, 10),
			DeptId:          strconv.FormatInt(application.DeptId, 10),
			Type:            application.Type,
			Status:          application.Status,
			ApplyType:       dao.ApplicationDetailTypeString(application.Type),
			ApplyStatus:     dao.ApplicationStatusString(application.Status),
			Note:            application.Note,
			ApplicationType: application.ApplicationType,
		}

		c.JSON(http.StatusOK, model.SuccessObject("操作成功", result))
		global.Log.Info("ApplicationApprove success.", zap.Any("result", result))

		var op entity.OperatingRecord
		op.EmployeeId = application.ApplicantId
		op.Event = "加班申请审批 [status:" + strconv.Itoa(application.Status) + "] 审批人:" + fmt.Sprint(application.ApproverId)
		dao.InsertOpRecord(op)
	}
}

// ********************************************
// Func  ：批量审批申请（通过或拒绝）
// Method：POST
// Usage ：
// Param: overtimeId、approverId、status
// ********************************************
func ApplicationApproveBatch(c *gin.Context) {

	//todo .此处需要判别当前请求发起者身份，如果非主管和Hr，则驳回，无此操作权限
	requester := c.MustGet("USER").(*entity.Employee) //请求人
	if requester.Role != entity.EEmployeeRole_DeptLeader && requester.Role != entity.EEmployeeRole_Hr {
		global.Log.Error("ApplicationApproveBatch role error.")
		c.JSON(http.StatusOK, model.Fail("HR或部门主管审批请假"))
		return
	}

	var appList []entity.Application
	var err error

	// todo 这里要获取审批者的id，并判断权限
	approverId := requester.Id
	if approverId <= 0 {
		global.Log.Error("ApplicationApproveBatch approver id is lost!")
		c.JSON(http.StatusOK, model.Fail("审批人ID为空"))
		return
	}
	idListStr := c.DefaultPostForm("applicationIdList", "")
	if len(idListStr) <= 0 {
		global.Log.Error("ApplicationApproveBatch overtime is lost.")
		c.JSON(http.StatusOK, model.Fail("未指明申请ID"))
		return
	}
	status, err := strconv.Atoi(c.DefaultPostForm("status", ""))
	if err != nil {
		global.Log.Error("ApplicationApproveBatch status is error.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("未指明审批结果"))
		return
	}
	note := c.DefaultPostForm("note", "")

	idList := strings.Split(idListStr, ",")
	for _, idStr := range idList {
		var app entity.Application
		app.Id, err = strconv.ParseInt(idStr, 10, 64)
		if err != nil {
			global.Log.Error("ApplicationApproveBatch parse app id failed.", zap.Any("error", err))
			c.JSON(http.StatusOK, model.Fail("批量申请解析异常"))
			return
		}
		app.ApproveAt = time.Now()
		app.ApproverId = approverId
		app.Status = status
		app.Note = note
		appList = append(appList, app)
	}

	err = dao.UpdateApplicationBatch(appList, "status,approve_at,note,approver_id")
	if err != nil {
		global.Log.Error("ApplicationApproveBatch failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("批量审批失败"))
	} else {
		c.JSON(http.StatusOK, model.SuccessObject("操作成功", idList))
		global.Log.Info("ApplicationApproveBatch success.", zap.Any("approve batch", idList))

		var op entity.OperatingRecord
		op.EmployeeId = 0
		op.Event = "申请批量审批 [status:" + strconv.Itoa(status) + "] 审批人:" + fmt.Sprint(approverId)
		dao.InsertOpRecord(op)
	}
}

// ********************************************
// Func  ：召回任务或取消任务
// Method：POST
// Usage ：
// ********************************************
func ApplicationCancelOrRecall(c *gin.Context) {

	var app entity.Application
	var err error
	app.Id, err = strconv.ParseInt(c.DefaultPostForm("applicationId", ""), 10, 64)
	if err != nil {
		global.Log.Error("ApplicationCancelOrRecall applicationId is lost.")
		c.JSON(http.StatusOK, model.Fail("未指明申请ID"))
		return
	}

	appInfo, err := dao.QueryApplicationInfo(app.Id)
	if appInfo == nil {
		global.Log.Error("ApplicationCancelOrRecall applicationId failed.")
		c.JSON(http.StatusOK, model.Fail("召回申请失败"))
		return
	}
	if err != nil {
		global.Log.Error("ApplicationCancelOrRecall applicationId failed.")
		c.JSON(http.StatusOK, model.Fail("召回申请失败"))
		return
	}
	if appInfo.Status == entity.EOvertimeStatus_Recall ||
		appInfo.Status == entity.EOvertimeStatus_PassAndCancel ||
		appInfo.Status == entity.EOvertimeStatus_Delete {
		global.Log.Error("ApplicationCancelOrRecall status has cancle.")
		c.JSON(http.StatusOK, model.Fail("申请不能重复撤销"))
		return
	}

	app.ApplicationType = appInfo.ApplicationType
	app.Duration = appInfo.Duration
	app.ApplicantId = appInfo.ApplicantId
	app.ApproverId = appInfo.ApproverId

	status, err := strconv.Atoi(c.DefaultPostForm("status", ""))
	if err != nil {
		global.Log.Info("ApplicationCancelOrRecall status is missing.", zap.Any("error", err))
		if appInfo.Status == entity.EOvertimeStatus_Pass {
			app.Status = entity.EOvertimeStatus_PassAndCancel
			appInfo.Status = entity.EVacationStatus_PassAndCancel
		} else {
			app.Status = entity.EOvertimeStatus_Recall
			appInfo.Status = entity.EOvertimeStatus_Recall
		}
	} else {
		app.Status = status
		appInfo.Status = status
	}

	note := c.DefaultPostForm("note", "")
	if len(note) > 0 {
		app.Note += ("\n" + note) //合并批注信息内容
		appInfo.Note += ("\n" + note)
	}

	err = dao.UpdateApplication(app, "status,note")
	if err != nil {
		global.Log.Error("UpdateDepartment failed.", zap.Any("error", err))
		c.JSON(http.StatusOK, model.Fail("更新部门失败"))
	} else {
		output := &entity.OutputApplicationInfo{
			Id:              strconv.FormatInt(app.Id, 10),
			ApplicantId:     strconv.FormatInt(appInfo.ApplicantId, 10),
			ApproverId:      strconv.FormatInt(appInfo.ApproverId, 10), //审批人ID
			DeptId:          strconv.FormatInt(appInfo.DeptId, 10),     //部门ID
			Reason:          appInfo.Reason,
			StartDate:       appInfo.StartDate,
			EndDate:         appInfo.EndDate,
			Duration:        appInfo.Duration,
			CreateAt:        appInfo.CreateAt,
			ApproveAt:       appInfo.ApproveAt,
			Type:            appInfo.Type,            //类型 0、不限、1工作日、2周末、3法定假日、4其它
			Status:          appInfo.Status,          //0:draft，1：send；2：delete；3:recall，4:refuse
			Note:            appInfo.Note,            //备注
			ApplicationType: appInfo.ApplicationType, //类型
			ApplicantName:   appInfo.ApplicantName,   //申请人姓名
			ApproverName:    appInfo.ApproverName,    //审批人姓名
			DeptName:        appInfo.DeptName,        //部门名称	employee.id
			DurationDay:     appInfo.DurationDay,     // 时长（天，0.5起跳）
			ApplyType:       appInfo.ApplyType,       //类型 0、不限、1工作日、2周末、3法定假日、4其它
			ApplyStatus:     appInfo.ApplyStatus,     //0:draft，1：send；2：delete；3:recall，4:refuse
		}

		c.JSON(http.StatusOK, model.SuccessObject("操作成功", output))
		global.Log.Info("UpdateDepartment success.", zap.Any("update application", app))

		var op entity.OperatingRecord
		op.EmployeeId = app.ApplicantId
		op.Event = "取消申请 [status:" + strconv.Itoa(app.Status) + "]"
		dao.InsertOpRecord(op)
	}
}

func QueryApplicationTypes(c *gin.Context) {
	type ApplicationType struct {
		Id   int
		Type string
	}
	types := []*ApplicationType{}

	type1 := &ApplicationType{
		Id:   entity.EDetailType_Sick,
		Type: "病假",
	}
	types = append(types, type1)

	type2 := &ApplicationType{
		Id:   entity.EDetailType_Personal,
		Type: "事假",
	}
	types = append(types, type2)

	type3 := &ApplicationType{
		Id:   entity.EDetailType_Annual,
		Type: "年假",
	}
	types = append(types, type3)

	type4 := &ApplicationType{
		Id:   entity.EDetailType_Marriage,
		Type: "婚假",
	}
	types = append(types, type4)

	type5 := &ApplicationType{
		Id:   entity.EDetailType_Funeral,
		Type: "丧家",
	}
	types = append(types, type5)

	type6 := &ApplicationType{
		Id:   entity.EDetailType_Workday,
		Type: "工作日加班",
	}
	types = append(types, type6)

	type7 := &ApplicationType{
		Id:   entity.EDetailType_Weekend,
		Type: "周末加班",
	}
	types = append(types, type7)

	type8 := &ApplicationType{
		Id:   entity.EDetailType_OfficialHoliday,
		Type: "法定假日加班",
	}
	types = append(types, type8)

	type9 := &ApplicationType{
		Id:   entity.EDetailType_Unknow,
		Type: "其他",
	}
	types = append(types, type9)

	c.JSON(http.StatusOK, model.SuccessObject("操作成功", types))
}
